import jsonpath


class AssertUtil:
    """
    @staticmethod用于修饰类中的方法，使其可以再不创建类实例的情况下调用方法，这样做的好处是执行效率较高，当然也可像一般方法一样用实例调用该方法。该方法一般被成为静态方法。静态方法不可以引用类中的属性或方法，其参数列表也不需要约定的默认参数self。
一般来说，要使用某个类的方法，需要先实例化一个对象再调用方法。使用
@staticmethod和@classmethod，就可以不需要实例化，直接类名.方法名()调用。
@staticmethod不需要表示自身对象的self和自身类的cls参数，和使用函数一样。
@classmethod不需要self参数，但第一个参数需要是表示自身类的cls参数。
如果在@staticmethod中要调用到这个类的一些属性方法，只能直接类名.属性名或类名.方法名。
而@classmethod因为持有cls参数，可以用来调用类的属性，类的方法，实例化对象等，避免硬编码。
    """
    @staticmethod
    def equals( check_value, expect_value):
        """相等"""
        assert check_value == expect_value, f'{check_value} == {expect_value}'

    @staticmethod
    def less_than(check_value, expect_value):
        """小于"""
        assert check_value < expect_value, f'{check_value} < {expect_value}'

    @staticmethod
    def less_than_or_equals(check_value, expect_value):
        """小于等于"""
        assert check_value <= expect_value, f'{check_value} <= {expect_value}'

    @staticmethod
    def greater_than(check_value, expect_value):
        """大于"""
        assert check_value > expect_value, f'{check_value} > {expect_value}'

    @staticmethod
    def greater_than_or_equals(check_value, expect_value):
        """大于等于"""
        assert check_value >= expect_value, f'{check_value} >= {expect_value}'

    @staticmethod
    def not_equals(check_value, expect_value):
        """不等于"""
        assert check_value != expect_value, f'{check_value} != {expect_value}'

    @staticmethod
    def contains(check_value, expect_value):
        """包含"""
        assert expect_value in check_value, f'{expect_value} in {check_value}'

    @staticmethod
    def startswith(check_value, expect_value):
        """以什么开头"""
        assert str(check_value).startswith(str(expect_value)), f'{str(check_value)} startswith {str(expect_value)}'

    @staticmethod
    def endswith(check_value, expect_value):
        """以什么结尾"""
        assert str(check_value).endswith(str(expect_value)), f'{str(check_value)} endswith {str(expect_value)}'

    def extract_by_jsonpath(self, extract_value:dict, extract_expression:str):
        """
        根据jsonpath获取值
        :param extract_value: 等于res.json()
        :param extract_expression: 等于$.token
        :return: None 或提取的第一个值 或全部
        """
        if not isinstance(extract_expression, str):
            return extract_expression
        """
        isinstance() 函数，是Python中的一个内置函数，用来判断一个函数是否是一个已知的类型，类似 type()
        语法：isinstance(object,classinfo)
        参数：object : 实例对象。classinfo : 可以是直接或者间接类名、基本类型或者由它们组成的元组。
        返回值：如果对象的类型与参数二的类型（classinfo）相同则返回 True，否则返回 False
        """
        extract_value = jsonpath.jsonpath(extract_value,extract_expression)#jsonpath.jsonpath(需要取出值的原文,取值需要的jsonpath表达式)
        if not extract_expression:
            return
        elif len(extract_value) ==1:
            return extract_value[0]#用jsonpath取出来的值如果只有一个的话就会被用一个列表括起来
        else:
            return extract_value

    def validate_response(self,response,validate_check):
        """"校验结果"""
        for check in validate_check:
            for check_type,check_value in check.items():
                #第一个for循环是列表的for循环，上头这个for循环方式是字典的for循环
                #实际结果
                actual_value = self.extract_by_jsonpath(response,check_value[0])
                #预期结果
                expect_value = check_value[1]
                if check_type in ['eq','equals','equal']:
                    self.equals(actual_value,expect_value)
                elif check_type in ['lt','less_than']:
                    self.less_than(actual_value,expect_value)
                elif check_type in ['le','less_or_equals']:
                    self.less_than_or_equals(actual_value,expect_value)
                elif check_type in ['gt','greater_than']:
                    self.greater_than(actual_value,expect_value)
                elif check_type in ['ne','not_equal']:
                    self.not_equals(actual_value,expect_value)
                elif check_type in ['contains','con']:
                    self.contains(actual_value,expect_value)
                elif check_type in ['startswith']:
                    self.startswith(actual_value,expect_value)
                elif check_type in ['endswith','con']:
                    self.endswith(actual_value,expect_value)
                else:
                    print(f'{check_type} not valid check type')
